#include "predictor.h"

#include<iostream>
#include<sstream>
#include<fstream>
#include<stdio.h>
using namespace std;
branch_record_c::branch_record_c()
{

      is_taken=0;
      is_conditional=0;
      instruction_addr=0;
}
branch_record_c::~branch_record_c()
{
}


//predictor size definitions
#define LOCAL_HISTORY_DEPTH 1024
#define LOCAL_HISTORY_WIDTH 10
#define LOCAL_PREDICTOR_WIDTH 3
#define LOCAL_PREDICTOR_DEPTH 1024
#define CHOICE_PREDICTOR_DEPTH 4096
#define CHOICE_PREDICTOR_WIDTH 2
#define PATH_HISTORY_WIDTH 12
#define WEIGHTS_TABLE 57
//some global variables
int initflag=0;
int local_history[LOCAL_HISTORY_DEPTH];
int local_predictor[LOCAL_PREDICTOR_DEPTH];
bool local_prediction,percep_prediction,choice_prediction;
int perceptron_table[WEIGHTS_TABLE][PATH_HISTORY_WIDTH]; //ARCH
int choice_predictor[CHOICE_PREDICTOR_DEPTH];
int path_history;
int output_global = 0;
;
bool PREDICTOR::get_prediction( branch_record_c* br)
{

            bool prediction = true;
            //First call initalization
            if(initflag==0)
            {
              for(int i=0;i<LOCAL_HISTORY_DEPTH;i++)
                local_history[i]=0;
              for(int i=0;i<LOCAL_PREDICTOR_DEPTH;i++)
                local_predictor[i]=2;
              for(int i=0;i<WEIGHTS_TABLE;i++)
              {
                  for(int j=0;j<PATH_HISTORY_WIDTH;j++)
                    perceptron_table[i][j]=0;
              }
              for(int i=0;i<CHOICE_PREDICTOR_DEPTH;i++)
                choice_predictor[i]=3;
              path_history=0;
              initflag=1;

            }

            //predict branch
            if ((br->is_conditional))
            {

               //extract bits [11:2] of program counter
               int local_history_index=(br->instruction_addr&1023);
               //Get local prediction from succesive indexing of local history table and local prediction table
               local_prediction=local_predictor[local_history[local_history_index]]>>2;

               /***************************************************************
		perceptron lookup algorithm
		***************************************************************/

	        int	index, a;
		signed int product[100];
		signed int output = 0;
		product[0]=0;
		index = (br->instruction_addr >> 2) % WEIGHTS_TABLE;
		/***************************************************************
		Calculating yout = w[0] + sum (w[i]*x[i])
		****************************************************************/
		for (a=0; a < PATH_HISTORY_WIDTH; a++)
		{
				product[a] = (perceptron_table[index][a]) * ((path_history>>(PATH_HISTORY_WIDTH-1-a))&1);
				output += product[a];
				output_global= output;
		}
               	if(output>0)
                    percep_prediction=1;
               	else if (output<=0)
                	percep_prediction=0;

               choice_prediction=choice_predictor[path_history]>>1;
               cout<<"My Predictor:"<<choice_prediction<<" ";
               if(choice_prediction==0)
               {
                  cout<<"Prediction:"<<local_prediction;
                  return local_prediction;
               }
               else
               {
                   cout<<"Prediction:"<<percep_prediction;
                   return percep_prediction;
               }
             }

            return prediction;   // true for taken, false for not taken
}

    // Update the predictor after a prediction has been made.  This should accept
    // the branch record (br)
    // argument (taken) indicating whether or not the branch was taken.
void PREDICTOR::update_predictor( branch_record_c* br, bool taken)
{
        cout<<" Actually:"<<taken<<endl;
        int p1=0,p2=0;
        int local_history_index=(br->instruction_addr&1023);
        //update predictors and btb
        if(taken&&br->is_conditional)
        {
            if(local_predictor[local_history[local_history_index]]<7)
               local_predictor[local_history[local_history_index]]++;

            /*if(global_predictor[path_history]<3)
               global_predictor[path_history]++; */


        }
        else if(!taken&&br->is_conditional)
        {
            if(local_predictor[local_history[local_history_index]]>0)
              local_predictor[local_history[local_history_index]]--;


        }
        if(br->is_conditional)
        {
            int b;
  	    signed int t, x[200];
	    int theta;
	    theta = 1.93 * (12) + 14;
            int index = (br->instruction_addr >> 2) % WEIGHTS_TABLE;
	    int output = output_global;
	    if (taken)
		t = 1;
	    else
		t = -1;

		if (output < 0)
		output = (-1)*output;

		if (output <= theta || (output < 0 && t > 0) || (output >= 0 && t < 0))
		{


			for (b=0; b < PATH_HISTORY_WIDTH; b++)
			{
				if (((path_history>>(11-b))&1))
				x[b] = -1;
				else
				x[b] = 1;
				if (t == x[b])
				{
				    perceptron_table[index][b]++;
				}
				else
				{
				    perceptron_table[index][b]--;
				}
                                //ensuring limitation of perceptrons
				if (perceptron_table[index][b]> 127)
				perceptron_table[index][b] = 127;
				if (perceptron_table[index][b] < -128)
				perceptron_table[index][b] = -128;

			}

		}
        }
        int t=taken;
        // temp to store initial value of t
        int t1=t;
        t<<=9;
        //update local history
        if(br->is_conditional)
            local_history[local_history_index]=(local_history[local_history_index]>>1)|t;
        //Choice Predictor Update
        if(local_prediction==taken&&br->is_conditional)
            p1=1;
        else if(local_prediction!=taken&&br->is_conditional)
            p1=0;
        if(percep_prediction==taken&&br->is_conditional)
            p2=1;
        else if(percep_prediction!=taken&&br->is_conditional)
            p2=0;
        if((p1<p2)&&(choice_predictor[path_history]<3))
            choice_predictor[path_history]++;
        else if((p1>p2)&&(choice_predictor[path_history]>0))
            choice_predictor[path_history]--;
        t1<<=11;
        //update path history
        path_history=(path_history>>1)|t1;
  }
